#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>


#include "ClientThread.hpp"
#include "error.hpp"
/**
 * ClientThread
 **/
void ClientThread::run()
{
	int nbReady,i,recvSize;
	Client* eventClient;
	char buffer[5001];
	while('a')
	{
		// lock
		pthread_mutex_lock(&this->epLock);

		// wait a client connection
		if(!this->nbClients)
			pthread_cond_wait(&this->epCond,&this->epLock);

		// unlock
		pthread_mutex_unlock(&this->epLock);
		
		// epoll wait
		if((nbReady=epoll_wait (this->epfd, this->epollEvents,this->maxClients,1000))==-1)
			error((char*)"epoll_wait error");
		else
		{
			i=0;
			while(i<nbReady)
			{
				eventClient=this->clientManager->getClientBySfd(this->epollEvents[i].data.fd);
		//		cout << "epoll event : socket " << eventClient->sfd << endl;
				if((recvSize=recv(eventClient->sfd,buffer,5000,0))<0)
					error((char*)"recv error");
				else
				{
					if(recvSize==0)
					{
			//			cout << "connection closed\n";
						if(epoll_ctl (this->epfd, EPOLL_CTL_DEL,eventClient->sfd, &eventClient->epollEvent))
							error((char*)"epoll_ctl (delete)");
						close(eventClient->sfd);

						/** delete client **/
						this->clientManager->remove(eventClient);
						delete eventClient;
					}
					else
					{
						/* receiving data */
						buffer[recvSize]=0;

						/** send request to requestManager **/
						this->requestManager->addRequest(eventClient,buffer);

						/* wake the thread up */
						pthread_cond_signal(&this->requestManager->cond);
					}
				}
				++i;
			}
		}
	}
}

/**
 * add a client in the client thread
 * @param sfd client file descriptor
 * @return 1=ok , 0=error
 **/
int ClientThread::addClient(int sfd)
{
	Client* newClient;

	// lock
	pthread_mutex_lock(&this->epLock);

	// max client reached 
	if(this->nbClients==this->maxClients)
	{
		pthread_mutex_unlock(&this->epLock);
		return 0;
	}

	// increment nbClients
	++this->nbClients;

	// create new client

	
	newClient=new Client(sfd);
	
	/** add client : send to clientManager */
	this->clientManager->add(newClient);


	// add epoll event
	if(epoll_ctl (this->epfd, EPOLL_CTL_ADD,sfd, &newClient->epollEvent))
		error ((char*)"epoll_ctl");

	// unlock
	pthread_mutex_unlock(&this->epLock);

	// signal to the thread
	pthread_cond_signal(&this->epCond);
	
	// ok
	return 1;
}
ClientThread::ClientThread(int maxClients,RequestManager* requestManager,ClientManager* clientManager)
{
	this->maxClients=maxClients;
	this->requestManager=requestManager;
	this->clientManager=clientManager;

	// init epoll
	this->epfd=epoll_create(maxClients);
	if(epfd<0)
	{
		error((char*)"epoll_create @ ClientThread constructor");
		return;
	}

	// init epoll events array
	this->epollEvents=new struct epoll_event[maxClients];

	/* init lock & cond */
	pthread_mutex_init(&this->epLock,NULL);
	pthread_cond_init(&this->epCond,NULL);

}
